#include "dev_sf.h"

#define SF_LOCK(s)         do {\
                              if (s->lock == 1) return;\
                              else s->lock = 1;\
                            } while(0)

#define SF_UNLOCK(s)        do {\
                              s->lock = 0;\
                            } while(0)
#define RDSR  5
#define SPIx                      SPI4


bs_sf_dev_t spi_flash0;
static bs_sf_request_t *flash_wr_rquests[FLASH_WRITE_QUEUE_LENGTH];
// 任务队列的长度，第一个元素保存当前请求
static bs_sf_request_t *file_rd_requests[FILE_REAUEST_QUEUE_LENGTH];
extern uint32_t sf_lock;

/*!
    \brief 设备初始化、清空队列
    \param[in]  none
    \param[out] none
    \retval     none
*/
void bs_sf_device_init()
{
    int i;
    for (i=0; i<FILE_REAUEST_QUEUE_LENGTH+1; i++) file_rd_requests[i] = NULL;
    for (i=0; i<FLASH_WRITE_QUEUE_LENGTH; i++) flash_wr_rquests[i] = NULL;
}


/*!
    \brief 优先处理读请求
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_flash_read_nonblock(uint8_t* pbuffer, uint32_t read_addr, uint16_t size)
{
    spi_flash_buffer_read_dma(pbuffer, read_addr, size);
}


/*!
    \brief 擦除flash间隙调用：清空读请求，如何判断请求没有处理
    \param[in]  none
    \param[out] none
    \retval     none
*/
void spi_flash_check_read_queue()
{
    bs_sf_request_t *bd = file_rd_requests[0];
    if( spi_flash0.s_wait) {
        spi_flash0.s_wait = 0;
        spi_flash0.lock = 1;
        spi_flash_read_nonblock(bd->b_data, bd->b_addr, bd->b_size);
    }
}


/*!
    \brief 异常处理
    \param[in]  none
    \param[out] none
    \retval     none
*/
void bs_flash_err_handle(int code)
{
    __NOP();
    (void)code;
    return;
}


/*!
    \brief 将当前请求项插入到请求队列末尾，并立即返回
    \param[in]  none
    \param[out] none
    \retval     none
*/
void bs_sf_make_request(bs_sf_request_t *bd, int cmd)
{
    int i, j;
    if (cmd == 0) {
        __disable_irq();
        for (i=0; i<FILE_REAUEST_QUEUE_LENGTH; i++) {
            if (file_rd_requests[i] == NULL) {
                file_rd_requests[i] = bd;
                break;
            }
        }
        for (j=0; j<FILE_REAUEST_QUEUE_LENGTH-1; j++) {
            if (file_rd_requests[j] != NULL && file_rd_requests[j] == file_rd_requests[j+1]) {
                __NOP();
            }
        }
        __enable_irq();
        if (i==FILE_REAUEST_QUEUE_LENGTH) {
            bs_flash_err_handle(0);
        }
        if(i > 0) return;

        // 当前没有请求任务，立即执行，// 这里有没有可能flash正在忙？
        if(spi_flash0.lock == 1) {
            // 先不要启动，
            spi_flash0.s_wait = 1;
            return;
        }
        spi_flash0.lock = 1;
        spi_flash_read_nonblock(bd->b_data, bd->b_addr, bd->b_size);
    } else {
        __disable_irq();
        for (i=0; i<FLASH_WRITE_QUEUE_LENGTH; i++) {
            if (flash_wr_rquests[i] == NULL) {
                flash_wr_rquests[i] = bd;
                break;
            }
        }    
        __enable_irq();
        if (i==FLASH_WRITE_QUEUE_LENGTH) {
            bs_flash_err_handle(0);
        }
        if(i > 0) return;
    }
}


/*!
    \brief 传输完成回调 中断上下文
    \param[in]  none
    \param[out] none
    \retval
*/
void bs_dev_flash_isr(void) {
    bs_sf_request_t *bd;
    int i;
    spi_dma_disable(SPIx, SPI_DMA_RECEIVE);
    spi_dma_disable(SPIx, SPI_DMA_TRANSMIT);

    /* deselect the flash: chip select high */
    SPI_FLASH_CS_HIGH();
    bd = file_rd_requests[0];
    if (bd == NULL) {
        // error
        bs_flash_err_handle(1);
        return;
    }
    bd->b_lock = 0;
    bd->b_update = 1;
    sf_lock = 0;
    // 队列移动
    for (i = 0; i < FILE_REAUEST_QUEUE_LENGTH-1; i++)
    {
        if (file_rd_requests[i] == file_rd_requests[i + 1]) {
            __NOP();
        }
        file_rd_requests[i] = file_rd_requests[i + 1];
    }
    bd = file_rd_requests[0];
    if (bd == NULL) {
        spi_flash0.lock = 0;
        return;
    };
    spi_flash_read_nonblock(bd->b_data, bd->b_addr, bd->b_size);
    return;
}


/*!
    \brief 阻塞时用来查询当前队列状态
    \param[in]  none
    \param[out] none
    \retval
*/
// int bs_spiflash_ioctl() {

// }

/*!
    \brief 执行 flash 写入流程；如果上层程序要求同步写入，就不能用这个方法
    \brief 写操作一定是在主循环完成的
    \param[in]  none
    \param[out] none
    \retval
*/
void bs_spiflash_process(void) {
    int i;
    bs_sf_dev_t *sf_dev = &spi_flash0;
    bs_sf_request_t *write_req = sf_dev->cur_wr_req;
    //bs_sf_request_t *read_req = sf_dev->cur_rd_req;
    switch (sf_dev->state) {
        case SF_IDLE:
            spi_flash_check_read_queue();
            if (flash_wr_rquests[0] != NULL) {
                sf_dev->cur_wr_req = flash_wr_rquests[0];
                for (i = 0; i < FLASH_WRITE_QUEUE_LENGTH-1; i++)
                {
                    flash_wr_rquests[i] = flash_wr_rquests[i + 1];
                }
                sf_dev->state = SF_ERASER;
            }
        break;

        // 什么时候执行擦除工作？空闲的时候
        // 获得锁
        case SF_ERASER:
            SF_LOCK(sf_dev);
            spi_flash_sector_erase_nonblock(write_req->b_addr);
            sf_dev->state = SF_ERASER_BUSY;
        break;

        case SF_ERASER_BUSY:
            // 擦除是否完成？
            if((spi_flash_read_register(0x05) & 0x01) == 1) {
                // 超时处理
                break;
            }
            // 扇区擦除完成，释放锁, 检查读队列是否阻塞，清空读队列
            SF_UNLOCK(sf_dev);
            spi_flash_check_read_queue();
            sf_dev->state = SF_WRITE_PAGE;
        break;

        case SF_WRITE_PAGE:
            // 什么时候开启 write page呢？，直到读队列为空
            SF_LOCK(sf_dev);
            // 检查是否写完
            if(write_req->nr_sectors == 0) {
                sf_dev->state = SF_WRITE_SECTOR_CMPLT;
                break;
            }
            // 启动写数据过程，并等待 DMA 写入完成
            spi_flash_buffer_write_dma(write_req->b_data, write_req->b_addr, 256);
            write_req->b_data += 256;
            write_req->b_addr += 256;
            write_req->nr_sectors--;
            sf_dev->state = SF_WRITE_PAGE_BUSY;
        break;

        case SF_WRITE_PAGE_BUSY:
            // wait busy
            if((spi_flash_read_register(RDSR) & 0x01) == 1) {
                // 超时处理
                break;
            }
            // 当前页写入完成，清空读队列
            SF_UNLOCK(sf_dev);
            spi_flash_check_read_queue();
            sf_dev->state = SF_WRITE_PAGE;
        break;
        
        case SF_WRITE_SECTOR_CMPLT:
            // wait busy
            if((spi_flash_read_register(RDSR) & 0x01) == 1) {
                // 超时处理
                break;
            }
            SF_UNLOCK(sf_dev);
            // 当前block处理完
            sf_dev->state = SF_IDLE;
            write_req->b_lock = 0;
        break;

        default:
        break;
    }
}


void bs_sf_dev_sync() {
    // 同步，清空请求队列
}
